//
// Created by Mayn on 25-7-13.
//

#ifndef TOPGLWIDGET_H
#define TOPGLWIDGET_H

#include <QOpenGLWidget>
#include <QOpenGLFunctions>
#include <QOpenGLShaderProgram>
#include <QOpenGLBuffer>
#include <QMouseEvent>
#include <QWheelEvent>
#include <QVector2D>
#include <QVector3D>
#include <QMatrix4x4>
#include <QTimer>
#include <QTime>
#include <random>

#include "ViewState.h"
class TopGLWidget : public QOpenGLWidget, protected QOpenGLFunctions {
    Q_OBJECT
public:
    TopGLWidget(ViewState* viewState, QWidget* parent = nullptr)
        : QOpenGLWidget(parent), m_viewState(viewState) {
        setMouseTracking(true);
    }

protected:
    void initializeGL() override {
        initializeOpenGLFunctions();
        glClearColor(0.95f, 0.95f, 0.95f, 1.0f);

        // 创建着色器程序
        m_program = new QOpenGLShaderProgram(this);
        m_program->addShaderFromSourceCode(QOpenGLShader::Vertex,
            "attribute vec2 position;\n"
            "uniform mat4 projection;\n"
            "void main() {\n"
            "    gl_Position = projection * vec4(position, 0.0, 1.0);\n"
            "}");
        m_program->addShaderFromSourceCode(QOpenGLShader::Fragment,
            "uniform vec4 color;\n"
            "void main() {\n"
            "    gl_FragColor = color;\n"
            "}");
        m_program->link();

        // 创建VBO
        m_vbo.create();
    }

    void resizeGL(int w, int h) override {
        glViewport(0, 0, w, h);
        m_width = w;
        m_height = h;
        updateProjection();
    }

    void paintGL() override {
        glClear(GL_COLOR_BUFFER_BIT);

        if (!m_program->bind()) {
            return;
        }

        m_program->setUniformValue("projection", m_projection);

        drawRulers();
        drawMouseIndicators();

        m_program->release();
    }

    void mouseMoveEvent(QMouseEvent* event) override {
        QPointF pos = event->position();
        if (event->buttons() & Qt::LeftButton) {
            float deltaX = (pos.x() - m_lastMousePos.x()) / m_viewState->scale();
            m_viewState->setOffsetX(m_viewState->offsetX() - deltaX);
            updateProjection();
            update();
        }
        m_mousePos = pos;
        m_lastMousePos = pos;
        update();
    }

    void mousePressEvent(QMouseEvent* event) override {
        if (event->button() == Qt::LeftButton) {
            m_lastMousePos = event->position();
        }
    }

    void wheelEvent(QWheelEvent* event) override {
        QPoint numDegrees = event->angleDelta() / 8;
        if (!numDegrees.isNull()) {
            float zoomFactor = numDegrees.y() > 0 ? 1.1f : 0.9f;
            float oldScale = m_viewState->scale();
            float newScale = qBound(10.0f, oldScale * zoomFactor, 500.0f);
            m_viewState->setScale(newScale);

            // 计算鼠标在世界坐标中的位置
            QPointF mousePos = event->position();
            float worldX = (mousePos.x() - m_width/2.0f) / oldScale + m_viewState->offsetX();

            // 调整偏移量以保持鼠标位置的世界坐标不变
            m_viewState->setOffsetX(worldX - (mousePos.x() - m_width/2.0f) / newScale);

            updateProjection();
            update();
        }
    }

private:
    void updateProjection() {
        m_projection.setToIdentity();
        m_projection.ortho(-m_width/2.0f, m_width/2.0f,
                          -m_height/2.0f, m_height/2.0f,
                          -1.0f, 1.0f);
    }

    void drawRulers() {
        // 计算可见范围
        float leftWorld = m_viewState->offsetX() - m_width/(2.0f * m_viewState->scale());
        float rightWorld = m_viewState->offsetX() + m_width/(2.0f * m_viewState->scale());

        int startCm = static_cast<int>(std::floor(leftWorld));
        int endCm = static_cast<int>(std::ceil(rightWorld));

        const float rulerHeight = 30.0f;

        // 绘制上下标尺背景
        drawRect(-m_width/2.0f, m_height/2.0f - rulerHeight,
                m_width, rulerHeight, QVector4D(0.7f, 0.7f, 0.7f, 1.0f));
        drawRect(-m_width/2.0f, -m_height/2.0f,
                m_width, rulerHeight, QVector4D(0.7f, 0.7f, 0.7f, 1.0f));

        for (int cm = startCm; cm <= endCm; cm++) {
            float xPos = (cm - m_viewState->offsetX()) * m_viewState->scale();
            float tickHeight = (cm % 5 == 0) ? 20.0f : 10.0f;

            // 上标尺刻度
            drawLine(xPos, m_height/2.0f,
                    xPos, m_height/2.0f - tickHeight,
                    QVector4D(0.0f, 0.0f, 0.0f, 1.0f));

            // 下标尺刻度
            drawLine(xPos, -m_height/2.0f,
                    xPos, -m_height/2.0f + tickHeight,
                    QVector4D(0.0f, 0.0f, 0.0f, 1.0f));
        }
    }

    void drawMouseIndicators() {
        // 计算鼠标位置的世界坐标
        float mouseWorldX = (m_mousePos.x() - m_width/2.0f) / m_viewState->scale() + m_viewState->offsetX();

        // 计算三条垂直线位置
        float centerX = (mouseWorldX - m_viewState->offsetX()) * m_viewState->scale();
        float leftX = ((mouseWorldX - 0.5f) - m_viewState->offsetX()) * m_viewState->scale();
        float rightX = ((mouseWorldX + 0.5f) - m_viewState->offsetX()) * m_viewState->scale();

        // 绘制三条垂直线（不填充半透明区域）
        drawLine(leftX, -m_height/2.0f, leftX, m_height/2.0f,
                QVector4D(0.0f, 1.0f, 0.0f, 0.5f));
        drawLine(centerX, -m_height/2.0f, centerX, m_height/2.0f,
                QVector4D(0.0f, 1.0f, 0.0f, 1.0f));
        drawLine(rightX, -m_height/2.0f, rightX, m_height/2.0f,
                QVector4D(0.0f, 1.0f, 0.0f, 0.5f));
    }

    void drawLine(float x1, float y1, float x2, float y2, const QVector4D& color) {
        QVector<QVector2D> verts = {
            QVector2D(x1, y1),
            QVector2D(x2, y2)
        };

        m_vbo.bind();
        m_vbo.allocate(verts.constData(), verts.size() * sizeof(QVector2D));

        m_program->enableAttributeArray(0);
        m_program->setAttributeBuffer(0, GL_FLOAT, 0, 2, 0);
        m_program->setUniformValue("color", color);

        glDrawArrays(GL_LINES, 0, verts.size());

        m_vbo.release();
    }

    void drawRect(float x, float y, float width, float height, const QVector4D& color) {
        QVector<QVector2D> verts = {
            QVector2D(x, y),
            QVector2D(x + width, y),
            QVector2D(x + width, y + height),
            QVector2D(x, y + height)
        };

        m_vbo.bind();
        m_vbo.allocate(verts.constData(), verts.size() * sizeof(QVector2D));

        m_program->enableAttributeArray(0);
        m_program->setAttributeBuffer(0, GL_FLOAT, 0, 2, 0);
        m_program->setUniformValue("color", color);

        glDrawArrays(GL_TRIANGLE_FAN, 0, verts.size());

        m_vbo.release();
    }

private:
    ViewState* m_viewState;
    QOpenGLShaderProgram* m_program = nullptr;
    QOpenGLBuffer m_vbo{QOpenGLBuffer::VertexBuffer};
    QMatrix4x4 m_projection;
    QPointF m_mousePos;
    QPointF m_lastMousePos;
    int m_width = 0;
    int m_height = 0;
};


#endif //TOPGLWIDGET_H
